﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.IO;
using System.Reflection;

namespace AMatysiak.XML
{
    public abstract class Settings<T>
    {
        public delegate void AppSettingsEventHander(Settings<T> settings, SettingsEventArgs e);

        public event AppSettingsEventHander SettingsEvent;

        [NonSerialized]
        private string path;
        [XmlIgnore]
        public string Path
        {
            get { return path; }
            set { path = value; }
        }

        public Settings() { }

        public Settings(string path)
        {
            this.Path = path;
            this.Load();
        }

        public bool Save()
        {
            try
            {
                serialize();
            }
            catch (FileNotFoundException fex)
            {
                raiseEvent(SettingsEventReason.FileNotFound, fex);
                return false;
            }
            catch (Exception ex)
            {
                raiseEvent(SettingsEventReason.OtherException, ex);
                return false;
            }

            return true;
        }

        private void serialize()
        {
            Type type = typeof(T);
            XmlSerializer xs = new XmlSerializer(type);
            FileStream fs = new FileStream(this.Path, FileMode.Create);
            xs.Serialize(fs, this);
            fs.Close();
        }

        private void raiseEvent(SettingsEventReason reason, Exception ex)
        {
            if (SettingsEvent != null)
            {
                SettingsEventArgs e = new SettingsEventArgs(reason, ex);
                SettingsEvent(this, e);
            }
        }

        public bool Load()
        {
            try
            {
                deserialize();
            }
            catch (FileNotFoundException fex)
            {
                raiseEvent(SettingsEventReason.FileNotFound, fex);
                return false;
            }
            catch (Exception ex)
            {
                raiseEvent(SettingsEventReason.OtherException, ex);
                return false;
            }

            return true;
        }

        private void deserialize()
        {
            T settings;
            Type type = typeof(T);
            XmlSerializer xs = new XmlSerializer(type);
            FileStream fs = new FileStream(this.Path, FileMode.Open);
            settings = (T)xs.Deserialize(fs);

            foreach (FieldInfo fi in type.GetFields())
            {
                try
                {
                    fi.SetValue(this, fi.GetValue(settings));
                }
                catch
                {
                    fi.SetValue(this, null);
                }
            }

            fs.Close();
        }
    }

    public class SettingsEventArgs : EventArgs
    {
        public SettingsEventReason EventReason
        {
            get;
            protected set;
        }

        public object ObjInfo
        {
            get;
            protected set;
        }

        public SettingsEventArgs(SettingsEventReason reason, object objInfo)
        {
            this.EventReason = reason;
            this.ObjInfo = objInfo;
        }
    }

    public enum SettingsEventReason
    {
        FileNotFound = 1,
        OtherException = 99
    }
}
